﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SilverTile;
using System.Windows.Media.Imaging;
using SilverTile.Sprites;
using SilverTile.Xaml;

namespace SilverTileTests
{

    [TestClass]
    public class SpriteTests
    {

        [TestMethod]
        public void Sprite_Should_Have_Constructor_That_Sets_Size()
        {

            int expectedWidth = 20;
            int expectedHeight = 30;

            ISprite sprite = new Sprite(expectedWidth, expectedHeight);

            Assert.AreEqual(expectedWidth, sprite.Width, "Width should be " + expectedWidth);
            Assert.AreEqual(expectedHeight, sprite.Height, "Height should be " + expectedHeight);

        }

        [TestMethod]
        public void Sprite_Should_Implement_ISprite_And_IUpdateable()
        {
            var sprite = new Sprite(1, 1);
            Assert.IsInstanceOfType(sprite, typeof(ISprite), "Sprite is not ISprite");
            Assert.IsInstanceOfType(sprite, typeof(IUpdateable), "Sprite is not IUpdateable");
        }

        [TestMethod]
        public void Sprite_Should_Expose_Pixels_Property_With_Correct_Length()
        {

            int expectedWidth = 20;
            int expectedHeight = 30;

            ISprite sprite = new Sprite(expectedWidth, expectedHeight);

            Assert.IsNotNull(sprite.Pixels, "Pixels is null");
            Assert.AreEqual(expectedWidth * expectedHeight, sprite.Pixels.Length, "Pixels length should be " + expectedWidth * expectedHeight);
          
        }

        [TestMethod]
        public void Sprite_Should_Have_A_Position_That_Can_Be_Changed()
        {

            ISprite sprite = new Sprite(2, 2);

            Assert.AreEqual(0, sprite.X, "Sprite X doesn't start at 0");
            Assert.AreEqual(0, sprite.Y, "Sprite Y doesn't start at 0");

            int newX = 10;
            int newY = 12;
            sprite.X = newX;
            sprite.Y = newY;

            Assert.AreEqual(newX, sprite.X, "Sprite X wasn't changed to " + newX);
            Assert.AreEqual(newY, sprite.Y, "Sprite Y wasn't changed to " + newY);

        }

        [TestMethod]
        public void Sprite_Instansiated_From_An_Image_Resource_Should_Be_Set_Up_Correctly()
        {

            Uri imgUri = new Uri("/SilverTileTests;component/Tiles/0002.png", UriKind.Relative);

            ISprite sprite = new Sprite(imgUri);

            BitmapImage img = new BitmapImage();
            img.SetSource(Application.GetResourceStream(imgUri).Stream);

            Assert.AreEqual(img.PixelWidth, sprite.Width, "Sprite width was not set correctly");
            Assert.AreEqual(img.PixelHeight, sprite.Height, "Sprite height was not set correctly");

            WriteableBitmap wb = new WriteableBitmap(img);

            CollectionAssert.AreEqual(wb.Pixels, sprite.Pixels, "Sprite pixels are not equal to source images pixels");

        }

        [TestMethod]
        public void Many_Sprites_Should_Be_Able_To_Share_The_Same_Frame()
        {

            IFrame frame = new Frame("/SilverTileTests;component/Tiles/0002.png");
            ISprite sprite1 = new Sprite(frame);
            ISprite sprite2 = new Sprite(frame);

            // Change a pixel in the frame - this shold affect both sprites
            frame.Pixels[10] = 0;

            Assert.AreEqual(sprite1.Width, sprite2.Width, "Sprite 1 and 2 have different widths");
            Assert.AreEqual(sprite1.Height, sprite2.Height, "Sprite 1 and 2 have different heights");

            CollectionAssert.AreEqual(sprite1.Pixels, sprite2.Pixels, "Sprite 1 and 2 have different pixels");
            
        }

        [TestMethod]
        public void Sprite_Should_Have_Origin_X_And_Y_At_Default_0_0()
        {

            ISprite sprite = new Sprite(20, 20);
            Assert.AreEqual(0, sprite.OriginX, "Sprite does not have default OriginX at 0");
            Assert.AreEqual(0, sprite.OriginY, "Sprite does not have default OriginY at 0");

        }

        [TestMethod]
        public void Sprite_Should_Have_Origin_Set_From_Its_Frame()
        {

            IFrame frame1 = new Frame("/SilverTileTests;component/Tiles/0002.png");
            IFrame frame2 = new Frame("/SilverTileTests;component/Tiles/0002.png")
            {
                OriginX = 10,
                OriginY = 20
            };

            ISprite sprite1 = new Sprite(frame1);
            ISprite sprite2 = new Sprite(frame2);

            Assert.AreEqual(frame1.OriginX, sprite1.OriginX, "Sprite1 does not have same OriginX as its frame");
            Assert.AreEqual(frame1.OriginY, sprite1.OriginY, "Sprite1 does not have same OriginY as its frame");

            Assert.AreEqual(frame2.OriginX, sprite2.OriginX, "Sprite2 does not have same OriginX as its frame");
            Assert.AreEqual(frame2.OriginY, sprite2.OriginY, "Sprite2 does not have same OriginY as its frame");
            
        }

        [TestMethod]
        public void Sprite_Should_Have_Settable_IsVisible_Property()
        {

            ISprite sprite = new Sprite(10, 10);

            Assert.IsTrue(sprite.IsVisible, "IsVisible is False when it should be true");

            sprite.IsVisible = false;
            Assert.IsFalse(sprite.IsVisible, "IsVisible is True when it should be false");

        }

        [TestMethod]
        public void Sprite_Size_Should_Use_Frame_Size()
        {

            IFrame frame = new Frame(20, 20);
            ISprite sprite = new Sprite(frame);

            Assert.AreEqual(frame.Width, sprite.Width, "Sprite width and frame width are not equal");
            Assert.AreEqual(frame.Height, sprite.Height, "Sprite height and frame height are not equal");

        }

    }
}
